/*四边形不等式
* 1.四边形不等式
    定义方式1:若 a≤b≤c≤d，而且 W(a,d)+W(b,c)≥W(a,c)+W(b,d)，则称函数W(x,y)满足四边形不等式
    (单调性)        不等号成立:W(x, y)=(x+y)^2
    定义方式2.对于 ∀a<b∈Z+，都有 a<a+1≤b<b+1。这里分别把a,a+1,b,b+1视为刚刚的a,b,c,d，如果W(a,b+1)+W(a+1,b)≥W(a,b)+W(a+1,b+1)，那么W满足四边形不等式
    (函数本身具有四边形不等式关系)

* 2.dp转移方程:f[i]=min(0≤j<i)f[j]+V(j, i);
    如果V(j, i)满足四边形不等式，那么f[i]的最优决策具有单调性
    即：如果p[i]表示f[i]取到的最优解的j，则p[i]单调不递减。
    如果q决策在i取到k的时候比他前面的所有决策都好，那么q在i'>k时仍然比他前面的所有决策更好
    因此决策p[]一定是单调的
    所以dp转移方程可以优化为f[i]=f[p[i]]+V(p[i], i);

    用单调队列维护
        对于每个i，我们将其插入队列中时，可以直接将所有比i差的决策都出队，直到i不比队头的决策更优，
        那么如果队头决策比i更优，则直接把队头元素后面的所有决策改成i
        否则我们可以在队头的 [l,r]中二分查找，找到一个位置pos ，使得pos前面的所有决策都比i更优，
        后面决策i更优，然后将pos后面的所有决策都改为i
        同时，我们不需要在在队列中保存 1∼i 的部分，我们可以直接将其出队
        这样我们在计算fi的时候，直接取队头元素，就是最优决策

* 本题:
    状态转移方程: f[i]=min(0≤j<i)f[j]+|s[i]−s[j]+i−j−1−L|^P
    定义V(j,i)为 |s[i]−s[j]+i−j−1−L|^P
    令 u=V(j,i),v=V(j+1,i)
    问题转换为 |v|^(P)−|v+ai+1|^(P)≥|u|^(P)−|u+ai+1+1|^(P)
    易证，可推出V满足四边形不等式
*/

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define DEBUG
using ld=long double;
inline int read()
{
	int x=0;char c=getchar();
	while (c<'0'||c>'9') c=getchar();
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48,c=getchar();
	return x;
}
inline void write(int x)
{
	if (x>=10) write(x/10);
	putchar(x%10+48);
}//快读快输
const int N=1e5+10, M=31e5+10;

int n, L, P;
ld f[N]; //排完前i个字符串的最小代价
char str[N][31];
int s[N], opt[N]; //前i个字符串的总长度 排完前i个字符串时，使得代价最小的上一个字符串的位置
struct node
{
    int pos, l, r; //位置 左边界 右边界
}q[N];
int hh, tt;

ld V(int j, int i) //将字符串从位置j到位置i放在一行时的代价
{
    ld res=1, a=abs(s[i]-s[j]+i-j-1-L);
    for(int i=0; i<P; i++) res*=a; //累乘p次
    return res+f[j]; //这一行的代价+排完前j个字符串的最小代价
}

void insert(int i) //维护单调队列，使得队列中的元素（代表不同的排版方案）按照代价从低到高排列
{
    int pos=n+1;
    while(hh<=tt && V(q[tt].pos, q[tt].l)>=V(i, q[tt].l)) pos=q[tt--].l; //从队尾弹出代价高的
    if(hh<=tt && V(q[tt].pos, q[tt].r)>=V(i, q[tt].r)) //队尾权值可以被更新
    {
        int l=q[tt].l, r=q[tt].r;
        while(l<r)
        {
            int mid=l+r>>1;
            if(V(q[tt].pos, mid)>=V(i, mid)) r=mid;
            else l=mid+1;
        }
        q[tt].r=r-1;
        pos=r;
    }
    if(pos!=n+1) q[++tt]={i, pos, n};
}

void solve()
{
    n=read(), L=read(), P=read();
    for(int i=n; i>=1; i--) scanf("%s", str[i]);
    for(int i=1; i<=n; i++) s[i]=s[i-1]+strlen(str[i]);
    hh=tt=0;
    q[0]={0, 1, n};
    for(int i=1; i<=n; i++)
    {
        f[i]=V(q[hh].pos, i), opt[i]=q[hh].pos; //前i个字符串的最小代价 对应的上一个字符串的位置opt[i]
        if(q[hh].r==i) hh++; //删掉队头
        q[hh].l=i+1;
        insert(i); //维护单调队列
    }

    if(f[n]>1e18) puts("Too hard to arrange");
    else
    {
        printf("%lld\n", (long long)f[n]);
        for(int i=n; i; i=opt[i])
        {
            for(int j=i; j>opt[i]; j--)
            {
                printf("%s", str[j]);
                if(j!=opt[i]+1) putchar(' ');
            }
            puts("");
        }
    }
    puts("--------------------");
}

signed main()
{
    #ifdef DEBUG
        freopen("./in.txt","r",stdin);
        freopen("./out.txt","w",stdout);
    #endif

    
    int T=1; T=read();
    while(T--)
    {
        solve();
    }
    return 0;
}